#include <iostream>
#include <functional>
#include <memory>
#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "CalCulate.hpp"

using namespace protocol_ns;

using callback_t = std::function<Response(const Request &)>;

void Usage(const std::string &proc)
{
    std::cout << "usage:\n\t" << proc << " local_port\n"
              << std::endl;
    return;
}

class Service
{
public:
    Service(callback_t cb) : _cb(cb)
    {
    }

    void ServiceHellper(socket_sptr sockptr, InetAddr addr)
    {
        int sockfd = sockptr->SockFd();
        LOG(DEBUG, "get a new link, sockfd: %d\n", sockfd);

        std::string clientaddr = '[' + addr.Ip() + ':' + std::to_string(addr.Port()) + ']';
        std::string inbuffer;
        while (true)
        {
            int n = sockptr->Recv(&inbuffer); // 不一定是完整的请求
            if (n < 0)
            {
                LOG(DEBUG, "client %s quit", clientaddr.c_str());
                break;
            }
            std::string package;
            while (true) // 一次处理完已经收到的所有请求
            {
                // 1.获取完整的请求
                package = Decode(inbuffer);
                if (package == "")
                    break;

                // 2.反序列化
                Request req;
                req.Deserialize(package);

                // 3.处理任务
                Response resp = _cb(req);

                // 4.序列化处理结果
                std::string outbuffer;
                resp.Serialize(&outbuffer);
                std::cout << "resp Serialize:" << std::endl;
                std::cout << outbuffer << std::endl;

                // 5.协议化 发送
                outbuffer = Encode(outbuffer);
                std::cout << "resp Encode:" << std::endl;
                std::cout << outbuffer << std::endl;
                sockptr->Send(outbuffer); // 本次不对发送做处理， EPOLL
            }
        }
    }

private:
    callback_t _cb;
};

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERROR);
    }
    uint16_t port = std::stoi(argv[1]);

    // 将当前进程转换为守护进程（daemon）
    // int daemon(int nochdir, int noclose);
    // nochdir: 设置为 0，守护进程会将当前工作目录更改为根目录 (/)，避免在文件系统卸载时出现问题。
    // noclose: 如果设置为非零值，则守护进程不会关闭标准输入、标准输出和标准错误输出。设为 0，守护进程会关闭这些文件描述符，确保守护进程不会意外地输出到终端。

    daemon(0, 0);
    EnableFile();

    Calculate cal;
    Service calservice(std::bind(&Calculate::Excute, &cal, std::placeholders::_1));                                        // 应用层
    io_service_t service = std::bind(&Service::ServiceHellper, &calservice, std::placeholders::_1, std::placeholders::_2); // 表示层
    std::unique_ptr<TcpServer> usvr = std::make_unique<TcpServer>(port, service);                                          // 会话层

    usvr->Loop();
}